import * as css from 'css'

let currentToken = null
let currentAttribute = null
let currentTextNode = null
let stack = [{type: 'document', children: []}] // 先保存一个初始的节点

const EOF = Symbol("EOF") // EOF: End of File 利用Symbol唯一性特点

// 加入一个新的函数， 把css规则暂时存到一个数组里
let rules = []
function addCSSRules(text) {
  var ast = css.parse(text) // 先变成 AST 抽象树
  // console.log(JSON.stringify(ast, null, "    "))
  rules.push(...ast.stylesheet.rules)
}

function computeCSS(element) {
  console.log(rules)
  console.log('compute CSS for Element', element)
}

function emit(token) { // 输出函数(构建dom树)  可以参考 Tree construction 的输出规则
  console.log(token)
  let top = stack[stack.length - 1] // 先把栈顶 取出来 就是最后一个元素

  if (token.type == 'startTag') {
    let element = {
      type: 'element',
      children: [],
      attributes: []
    }
    element.tagName = token.tagName

    for (let p in token) {
      if (p != 'type' && p != 'tagName') {
        element.attributes.push({
          name: p,
          value: token[p]
        })
      }
    }
    computeCSS(element)

    top.children.push(element)
    // element.parent = top

    if (!token.isSelfClosing)
      stack.push(element)
    
    currentTextNode = null // 清空文本节点
  
  } else if (token.type == 'endTag') {
    if (top.tagName != token.tagName) { // 如果不配对就抛出错误
      throw new Error("Tag start end doesn't match!")
    } else {
      // ---------------遇到style标签时，执行添加CSS规则的操作---------------
      if (top.tagName === 'style') { // 暂时不考虑 link 标签
        addCSSRules(top.children[0].content)
      }
      stack.pop()
    }
    currentTextNode = null // 清空文本节点

  } else if (token.type === 'text') { // 文本节点
    if (currentTextNode == null) { // 如果没有文本节点就创建一个新的
      currentTextNode = {
        type: 'text',
        content: ''
      }
      top.children.push(currentTextNode)
    }
    currentTextNode.content += token.content
  }
}

function data(c) { // 状态机 用作状态迁移
  if (c == '<') { // 标签左尖括号为开始
    return tagOpen
  } else if (c == EOF) { // 结束
    emit({
      type: 'EOF'
    })
    return
  } else { // 其他字符当文本节点
    emit({ // 先一个一个的emit出去
      type: 'text',
      content: c
    })
    return data
  }
}

function tagOpen(c) { // 判断标签种类 开始标签、结束标签、自封闭标签
  if (c == '/') { // 判断是否是结束标签
    return endTagOpen
  } else if (c.match(/^[a-zA-Z]$/)) { // 开始标签 或自封闭标签
    currentToken = { // 赋一个初值
      type: 'startTag',
      tagName: ''
    }
    return tagName(c)
  } else {
    return
  }
}

function endTagOpen(e) {
  if (c.match(/^[a-zA-Z]$/)) {
    currentToken = { // 赋一个初值
      type: 'endTag',
      tagName: ''
    }
    return tagName(c)
  } else if (c == '>') {

  } else if (c == EOF) {

  } else {

  }
}

// <html prop
function tagName(c) {
  if (c.match(/^[\t\n\f ]$/)) { // 空白符结束，在html里有效的有：tab符、换行符、禁止符、空格
    return beforeAttributeName
  } else if (c == '/') { // 遇到 自封闭标签
    return selfClosingStartTag
  } else if (c.match(/^[a-zA-Z]$/)) {
    currentToken.tagName += c // 字符或字母就追加到tagName里面
    return tagName
  } else if (c =='>') { // 结束 返回到data 开始下一个标签
    return data
  } else {
    return tagName
  }
}

// 处理属性 <html mata=
function beforeAttributeName(c) {
  if (c.match(/^[\t\n\f ]$/)) {
    return beforeAttributeName
  } else if (c == '/' || c =='>' || c == EOF) { // 结束
    return afterAttributeName(c)
  } else if (c == '=') {
    // 错误 不会遇到 = 号
  } else { // 否则会遇到一个字符
    currentToken = {
      name: '',
      value: ''
    }
    return attributeName(c)
  }
}

function attributeName(c) {
  if (c.match(/^[\t\n\f ]$/) || c == '/' || c == '>' || c == EOF) {
    return afterAttributeName(c) // 相当于一个状态结束了
  } else if (c == '=') {
    return beforeAttributeValue
  } else if (c == '\u0000') {

  } else if (c == "\"" || c == "'" || c == '<') {

  } else {
    currentAttribute.name += c
    return attributeName
  }
}

function beforeAttributeValue(c) {
  if (c.match(/^[\t\n\f ]$/) || c == '/' || c == '>' || c == EOF) {
    return beforeAttributeValue
  } else if (c == '\"') {
    return doubleQuotedAttributeValue
  } else if (c == '\'') {
    return singleQuotedAttributeValue
  } else if (c == '>') {

  } else {
    return UnquotedAttributeValue(c)
  }
}

function doubleQuotedAttributeValue(c) {
  if (c == '\"') { // 只找 " 结束
    currentToken[currentAttribute.name] = currentAttribute.value
    return afterQuotedAttributeValue
  } else if (c == '\u0000') {

  } else if (c == EOF) {

  } else {
    currentAttribute.value += c
    return doubleQuotedAttributeValue
  }
}

function singleQuotedAttributeValue(c) {
  if (c == '\'') { // 只找 ' 结束
    currentToken[currentAttribute.name] = currentAttribute.value
    return afterQuotedAttributeValue
  } else if (c == '\u0000') {

  } else if (c == EOF) {

  } else {
    currentAttribute.value += c
    return doubleQuotedAttributeValue
  }
}

function afterQuotedAttributeValue(c) {
  if (c.match(/^[\t\n\f ]$/)) {
    return beforeAttributeName
  } else if (c == '/') {
    return selfClosingStartTag
  } else if (c == '>') {
    currentToken[currentAttribute.name] = currentAttribute.value
    emit(currentToken)
    return data
  } else if (c == EOF) {

  } else {
    currentAttribute.value += c
    return doubleQuotedAttributeValue
  }
}

function UnquotedAttributeValue(c) {
  if (c.match(/^[\t\n\f ]$/)) { // 只找 空白符 结束
    currentToken[currentAttribute.name] = currentAttribute.value
    return beforeAttributeName
  } else if (c == '/') {
    currentToken[currentAttribute.name] = currentAttribute.value
    return selfClosingStartTag
  } else if (c == '>') {
    currentToken[currentAttribute.name] = currentAttribute.value
    emit(currentToken)
    return data
  } else if (c == '\u0000') {

  } else if (c == '\"' || c == "'" || c == '<' || c == '=' || c == "`") {

  } else if (c == EOF) {

  } else {
    currentAttribute.value += c
    return UnquotedAttributeValue
  }
}

// 分析到一个标签 <div / 只有一个 /了，
function selfClosingStartTag(c) {
  if (c =='>') {
    currentToken.isSelfClosing = true // 结束的时候给个true状态
    return data
  } else if (c =='EOF') {

  } else {

  }
}

function afterAttributeName(c) {
  if (c.match(/^[\t\n\f ]$/)) {
    return afterAttributeName
  } else if (c == '/') {
    return selfClosingStartTag
  } else if (c == '=') {
    return beforeAttributeValue
  } else if (c == '>') {
    currentToken[currentAttribute.name] = currentAttribute.value
    emit(currentToken)
    return data
  } else if (c == EOF) {

  } else {
    currentToken[currentAttribute.name] = currentAttribute.value
    currentAttribute = {
      name: '',
      value: ''
    }
    return attributeName(c)
  }
}


module.exports.parseHTML = function parseHTML(html) {
  let state = data // 初始状态一般命名为data
  for(let c of html) { // 对每个字符循环，并使用状态机进行判断处理
    state = state(c)
  }
  // 状态机 强迫一些节点结束 额外给一个无效的字符
  // (因为html最后会有文件终结，有的文本节点可能没有结束的状态)
  state = state(EOF)

  console.log(stack[0])
  return stack[0]
}

// 第一步：CSS计算 | 收集CSS规则
// 遇到style标签时，把css规则保存起来
// 调用css.parser 来分析css规则
// 必须要仔细研究此库分析css规则的格式


// 第二步：添加调用
// 当创建一个元素后，立即计算CSS
// 理论上，当分析一个元素时，所有CSS规则以及收集完毕
// 在真实浏览器中华可能遇到写在body的style标签，需要重新CSS计算的情况，先暂时忽略

